{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### LDA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "class LDA():\n",
    "    def __init__(self):\n",
    "        # 初始化权重矩阵\n",
    "        self.w = None\n",
    "        \n",
    "    # 计算协方差矩阵\n",
    "    def calc_cov(self, X, Y=None):\n",
    "        m = X.shape[0]\n",
    "        # 数据标准化\n",
    "        X = (X - np.mean(X, axis=0))/np.std(X, axis=0)\n",
    "        Y = X if Y == None else (Y - np.mean(Y, axis=0))/np.std(Y, axis=0)\n",
    "        return 1 / m * np.matmul(X.T, Y)\n",
    "    \n",
    "    # 对数据进行投影\n",
    "    def project(self, X, y):\n",
    "        self.fit(X, y)\n",
    "        X_projection = X.dot(self.w)\n",
    "        return X_projection\n",
    "    \n",
    "    # LDA拟合过程\n",
    "    def fit(self, X, y):\n",
    "        # 按类分组\n",
    "        X0 = X[y == 0]\n",
    "        X1 = X[y == 1]\n",
    "\n",
    "        # 分别计算两类数据自变量的协方差矩阵\n",
    "        sigma0 = self.calc_cov(X0)\n",
    "        sigma1 = self.calc_cov(X1)\n",
    "        # 计算类内散度矩阵\n",
    "        Sw = sigma0 + sigma1\n",
    "\n",
    "        # 分别计算两类数据自变量的均值和差\n",
    "        u0, u1 = np.mean(X0, axis=0), np.mean(X1, axis=0)\n",
    "        mean_diff = np.atleast_1d(u0 - u1)\n",
    "\n",
    "        # 对类内散度矩阵进行奇异值分解\n",
    "        U, S, V = np.linalg.svd(Sw)\n",
    "        # 计算类内散度矩阵的逆\n",
    "        Sw_ = np.dot(np.dot(V.T, np.linalg.pinv(np.diag(S))), U.T)\n",
    "        # 计算w\n",
    "        self.w = Sw_.dot(mean_diff)\n",
    "\n",
    "    \n",
    "    # LDA分类预测\n",
    "    def predict(self, X):\n",
    "        y_pred = []\n",
    "        for sample in X:\n",
    "            h = sample.dot(self.w)\n",
    "            y = 1 * (h < 0)\n",
    "            y_pred.append(y)\n",
    "        return y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn import datasets\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "data = datasets.load_iris()\n",
    "X = data.data\n",
    "y = data.target"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(80, 4) (20, 4) (80,) (20,)\n"
     ]
    }
   ],
   "source": [
    "X = X[y != 2]\n",
    "y = y[y != 2]\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=41)\n",
    "print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-0.38776207  1.27520386 -1.697222   -0.09784557]\n",
      "0.85\n"
     ]
    }
   ],
   "source": [
    "lda = LDA()\n",
    "lda.fit(X_train, y_train)\n",
    "y_pred = lda.predict(X_test)\n",
    "\n",
    "from sklearn.metrics import accuracy_score\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "print(accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1]"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.cm as cmx\n",
    "import matplotlib.colors as colors\n",
    "\n",
    "class Plot():\n",
    "    def __init__(self): \n",
    "        self.cmap = plt.get_cmap('viridis')\n",
    "\n",
    "    def _transform(self, X, dim):\n",
    "        covariance = calculate_covariance_matrix(X)\n",
    "        eigenvalues, eigenvectors = np.linalg.eig(covariance)\n",
    "        # Sort eigenvalues and eigenvector by largest eigenvalues\n",
    "        idx = eigenvalues.argsort()[::-1]\n",
    "        eigenvalues = eigenvalues[idx][:dim]\n",
    "        eigenvectors = np.atleast_1d(eigenvectors[:, idx])[:, :dim]\n",
    "        # Project the data onto principal components\n",
    "        X_transformed = X.dot(eigenvectors)\n",
    "\n",
    "        return X_transformed\n",
    "\n",
    "\n",
    "    def plot_regression(self, lines, title, axis_labels=None, mse=None, scatter=None, legend={\"type\": \"lines\", \"loc\": \"lower right\"}):\n",
    "        \n",
    "        if scatter:\n",
    "            scatter_plots = scatter_labels = []\n",
    "            for s in scatter:\n",
    "                scatter_plots += [plt.scatter(s[\"x\"], s[\"y\"], color=s[\"color\"], s=s[\"size\"])]\n",
    "                scatter_labels += [s[\"label\"]]\n",
    "            scatter_plots = tuple(scatter_plots)\n",
    "            scatter_labels = tuple(scatter_labels)\n",
    "\n",
    "        for l in lines:\n",
    "            li = plt.plot(l[\"x\"], l[\"y\"], color=s[\"color\"], linewidth=l[\"width\"], label=l[\"label\"])\n",
    "\n",
    "        if mse:\n",
    "            plt.suptitle(title)\n",
    "            plt.title(\"MSE: %.2f\" % mse, fontsize=10)\n",
    "        else:\n",
    "            plt.title(title)\n",
    "\n",
    "        if axis_labels:\n",
    "            plt.xlabel(axis_labels[\"x\"])\n",
    "            plt.ylabel(axis_labels[\"y\"])\n",
    "\n",
    "        if legend[\"type\"] == \"lines\":\n",
    "            plt.legend(loc=\"lower_left\")\n",
    "        elif legend[\"type\"] == \"scatter\" and scatter:\n",
    "            plt.legend(scatter_plots, scatter_labels, loc=legend[\"loc\"])\n",
    "\n",
    "        plt.show()\n",
    "\n",
    "\n",
    "\n",
    "    # Plot the dataset X and the corresponding labels y in 2D using PCA.\n",
    "    def plot_in_2d(self, X, y=None, title=None, accuracy=None, legend_labels=None):\n",
    "        X_transformed = self._transform(X, dim=2)\n",
    "        x1 = X_transformed[:, 0]\n",
    "        x2 = X_transformed[:, 1]\n",
    "        class_distr = []\n",
    "\n",
    "        y = np.array(y).astype(int)\n",
    "\n",
    "        colors = [self.cmap(i) for i in np.linspace(0, 1, len(np.unique(y)))]\n",
    "\n",
    "        # Plot the different class distributions\n",
    "        for i, l in enumerate(np.unique(y)):\n",
    "            _x1 = x1[y == l]\n",
    "            _x2 = x2[y == l]\n",
    "            _y = y[y == l]\n",
    "            class_distr.append(plt.scatter(_x1, _x2, color=colors[i]))\n",
    "\n",
    "        # Plot legend\n",
    "        if not legend_labels is None: \n",
    "            plt.legend(class_distr, legend_labels, loc=1)\n",
    "\n",
    "        # Plot title\n",
    "        if title:\n",
    "            if accuracy:\n",
    "                perc = 100 * accuracy\n",
    "                plt.suptitle(title)\n",
    "                plt.title(\"Accuracy: %.1f%%\" % perc, fontsize=10)\n",
    "            else:\n",
    "                plt.title(title)\n",
    "\n",
    "        # Axis labels\n",
    "        plt.xlabel('class 1')\n",
    "        plt.ylabel('class 2')\n",
    "\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "Plot().plot_in_2d(X_test, y_pred, title=\"LDA\", accuracy=accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.0\n"
     ]
    }
   ],
   "source": [
    "from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n",
    "clf = LinearDiscriminantAnalysis()\n",
    "clf.fit(X_train, y_train)\n",
    "y_pred = clf.predict(X_test)\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "print(accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
